package cn.kgc.appinfo.advice;

import cn.kgc.appinfo.entity.DevUser;
import cn.kgc.appinfo.entity.SysLog;
import cn.kgc.appinfo.service.SysLogService;
import lombok.extern.log4j.Log4j;
import org.apache.catalina.session.StandardSessionFacade;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.crypto.Data;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志通知类
 */
@Component  //将该类放入容器
@Aspect     //定义该类位Aspect类
@Log4j
public class SysLogAdvice {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private SysLogService sysLogService;

    private Date startTime;          //用户访问开始事件
    private Class visitClass;        //用户访问的类的Class对象
    private Method visistMethod;     //用户访问的方法对象

    //切入点表达式
    @Pointcut("execution(* cn.kgc.appinfo.controller.*.*(..))")
    public void sysLogPt(){}

    @Before("sysLogPt()")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        log.info("开启前置通知");
        //获取当前时间
        startTime = new Date();

        //获取我们访问的类的Class对象
        visitClass = jp.getTarget().getClass();

        log.info("访问的类"+visitClass);

        //获取我们访问的方法名
        String methodName = jp.getSignature().getName();

        log.info("访问方法名"+methodName);

        //获取我们访问的方法参数
        Object[] args = jp.getArgs();

        for (Object o:args) {
            log.info("方法的参数"+o.toString());
        }

        //如果参数为空，我们直接通过方法方法返回Method对象
        if(args.length == 0 || null == args){
            visistMethod = visitClass.getMethod(methodName);
        }else {
            //获得参数的Class对象
            Class[] argsClass = new Class[args.length];
            //遍历参数数组，获得各个参数的Class对象
            for (int i = 0; i < args.length ; i++) {
                argsClass[i] = args[i].getClass();
                if(args[i] instanceof BindingAwareModelMap){
                    argsClass[i] = Model.class;
                }
                if(args[i] instanceof StandardSessionFacade){
                    argsClass[i] = HttpSession.class;
                }
                if(args[i] instanceof CommonsMultipartFile){
                    argsClass[i] = MultipartFile.class;
                }
                if(args[i] instanceof DefaultMultipartHttpServletRequest){
                    argsClass[i] = HttpServletRequest.class;
                }
            }
            //通过方法名和参数Class对象，获取Method对象
            visistMethod = visitClass.getMethod(methodName,argsClass);
        }

    }

    @After("sysLogPt()")
    public void doAfter(){
        log.info("后置通知");

        StringBuilder url = new StringBuilder();
        //获取类上面定义的RequestMapping对象
        RequestMapping classAnnotation = (RequestMapping) visitClass.getAnnotation(RequestMapping.class);
//        classAnnotation.
        //获取类中定义的一级路径
        if(classAnnotation !=null){
            url.append(classAnnotation.value()[0]);
        }
        //获取方法上定义的RequestMappin对象
        RequestMapping methodAnnotation = visistMethod.getAnnotation(RequestMapping.class);
//        log.info("获取的url"+classAnnotation.value()[0]+methodAnnotation.value()[0]);
        //获取二级路径
        url.append(methodAnnotation.value()[0]);

        HttpSession session = request.getSession();
        String ipAddress = request.getRemoteAddr();

        DevUser devUser = (DevUser) session.getAttribute("user");
        //封装数据
        SysLog sysLog = new SysLog();
        sysLog.setOperateTime(startTime);
        if(devUser != null){
            sysLog.setUsername(devUser.getDevCode());
            sysLog.setUrl(url.toString());
            sysLog.setMethodName(visistMethod.getName());
            sysLog.setIpAddress(ipAddress);
            sysLog.setUserRoleName("开发者");
            sysLog.setVisitTime((int)(new Date().getTime() - startTime.getTime()));
            sysLogService.saveSysLog(sysLog);
        }








    }
}
